/**************************************************************************//**
 * @item     CosyOS Kernel
 * @file     sv_task.c
 * @brief    任务服务（仅在任务中调用）
 * @author   迟凯峰
 * @version  V3.3.5
 * @date     2023.09.18
 ******************************************************************************/

#include "os_var.h"
#include "os_api.h"
#include "os_iss.h"



/* 任务服务中触发任务调度（待返回后继续执行服务）*/
static void _task_scheduler_(void)
{
	vScheduling_f = true;
	mPSV_Trigger;
	mExitCritical;
	while(vScheduling_f);
	mEnterCritical;
}



/*
 * 任务
 */

/* 启动任务 */
tECODE __start_task(tspTaskHandle task_hand, u8 state)
{
	static tTID _SYS_MEM_ tid = 0;
	if(!task_hand->TID)
	{
		tid++;
		task_hand->TID = tid;
	}
	#if SYSCFG_TASKCREATEMODE == __STATIC__ \
	 || SYSCFG_TASKCREATEMODE == __BALANCE__
	task_hand->state = state;
	#elif SYSCFG_TASKCREATEMODE == __DYNAMIC__
	task_hand->task_node = (tspTaskNode)state;
	#endif
	vACTBUF = task_hand;
	vScheduling_f = true;
	mPSV_Trigger;
	mExitCritical;
	while(vScheduling_f);
	return vRET_f ? vACTRET : (tECODE)vTASKING->blocktype;
}

/* 恢复任务 */
tECODE __resume_task(tspTaskNode task_node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state & __SUSPENDED__)
	{
		task_node->state &= __RESUME__;
		if(task_node->state <= __FLOATING__ && task_node->TPL > vTASKING->TPL)
		{
			vScheduling_f = true;
			mPSV_Trigger;
		}
		mExitCritical;
		return ECODE_NOERR;
	}
	if(task_node->state < __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKUNSUSPENDED;
	}
	if(task_node->state & __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKSTOPPED;
	}
	if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	mExitCritical;
	return ECODE_DONOTKNOW;
}

/* 挂起任务 */
tECODE __suspend_task(tspTaskNode task_node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state < __SUSPENDED__)
	{
		task_node->state |= __SUSPENDED__;
		if(task_node == vTASKING)
		{
			vScheduling_f = true;
			mPSV_Trigger;
		}
		mExitCritical;
		return ECODE_NOERR;
	}
	if(task_node->state & __SUSPENDED__)
	{
		mExitCritical;
		return ECODE_TASKSUSPENDED;
	}
	if(task_node->state & __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKSTOPPED;
	}
	if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	mExitCritical;
	return ECODE_DONOTKNOW;
}

/* 删除任务 */
tECODE __delete_task(tspTaskNode task_node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state < __DELETED__)
	{
		task_node->state = __DELETED__;
		if(task_node == vTASKING)
		{
			vScheduling_f = true;
			mPSV_Trigger;
		}
		mExitCritical;
		return ECODE_NOERR;
	}
	if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	mExitCritical;
	return ECODE_DONOTKNOW;
}

/* 恢复指定任务并挂起自身任务 */
tECODE __ressus_task(tspTaskNode task_node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state & __SUSPENDED__)
	{
		task_node->state &= __RESUME__;
	}
	if(task_node->state <= __FLOATING__)
	{
		vTASKING->state |= __SUSPENDED__;
		vScheduling_f = true;
		mPSV_Trigger;
		mExitCritical;
		return ECODE_NOERR;
	}
	if(task_node->state < __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKNOTREADY;
	}
	if(task_node->state & __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKSTOPPED;
	}
	if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	mExitCritical;
	return ECODE_DONOTKNOW;
}

/* 设置任务优先级 */
tECODE __set_priority(tspTaskNode task_node, u8 tpl)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(task_node == NULL)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	#endif
	if(task_node->state < __STOPPED__)
	{
		if(task_node->TPL != tpl)
		{
			task_node->TPL = tpl;
			sSetPriority(task_node);
			if(tpl > vTASKING->TPL && task_node->state <= __FLOATING__)
			{
				vScheduling_f = true;
				mPSV_Trigger;
			}
			mExitCritical;
			return ECODE_NOERR;
		}
		else
		{
			mExitCritical;
			return ECODE_TPLUNCHANGED;
		}
	}
	if(task_node->state & __STOPPED__)
	{
		mExitCritical;
		return ECODE_TASKSTOPPED;
	}
	if(task_node->state == __DELETED__)
	{
		mExitCritical;
		return ECODE_TASKNOTSTARTED;
	}
	mExitCritical;
	return ECODE_DONOTKNOW;
}



/*
 * 延时
 */

/* 自身任务延时 */
void __delay(tDelay tc)
{
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __DELAY__;
	vScheduling_f = true;
	mPSV_Trigger;
	mExitCritical;
}

/* 设置延时 */
bool __set_delay(tspTaskNode task_node, tDelay tc)
{
	if(task_node->state == __BLOCKED__)
	{
		vDELAY_STMR[task_node->TID] = tc;
		mExitCritical;
		return true;
	}
	else
	{
		mExitCritical;
		return false;
	}
}

/* 清除延时 */
bool __clr_delay(tspTaskNode task_node)
{
	if(task_node->state == __BLOCKED__)
	{
		vDELAY_STMR[task_node->TID] = 0;
		task_node->state = __READY__;
		if(task_node->TPL > vTASKING->TPL)
		{
			vScheduling_f = true;
			mPSV_Trigger;
		}
		mExitCritical;
		return true;
	}
	else
	{
		mExitCritical;
		return false;
	}
}



/*
 * 互斥信号量
 */
#if SYSCFG_MUTEX == __ENABLED__
/* 释放 */
tECODE __free_mut(tspMut p)
{
	if(!p->mut)
	{
		mExitCritical;
		return ECODE_MUTEXISFREE;
	}
	if(vTASKING == p->node)
	{
		p->mut--;
		if(!p->mut)
		{
			if(vTASKING->TPL > p->tpl)
			{
				vTASKING->TPL = p->tpl;
				sSetPriority(vTASKING);
				vScheduling_f = true;
				mPSV_Trigger;
			}
		}
		mExitCritical;
		return ECODE_NOERR;
	}
	else
	{
		mExitCritical;
		return ECODE_NOPERMISSION;
	}
}

/* 获取 */
bool __take_mut(tspMut p, tDelay tc)
{
	if(!p->mut) goto __RET_TRUE1;
	if(vTASKING == p->node) goto __RET_TRUE2;
	if(!tc) goto __RET_FALSE;
	
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __MUTEX__ | 0x0F;
	vTASKING->ptr = p;
	if(vTASKING->TPL > p->node->TPL)
	{
		p->node->TPL = vTASKING->TPL;
		sSetPriority(p->node);
	}
	_task_scheduler_();
	p = (tspMut)vTASKING->ptr;
	if(!p->mut) goto __RET_TRUE1;
	
__RET_FALSE:
	mExitCritical;
	return false;
	
__RET_TRUE1:
	p->node = vTASKING;
	p->tpl = vTASKING->TPL;
	
__RET_TRUE2:
	p->mut++;
	mExitCritical;
	return true;
}

#endif



/*
 * 二值信号量
 */
#if SYSCFG_BINARY == __ENABLED__
/* 等待 */
bool __wait_bin(bool _XDATA_MEM_ *p, tDelay tc)
{
	if(*p) goto __RET_TRUE;
	if(!tc) goto __RET_FALSE;
	
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __BINARY__ | sizeof(bool);
	vTASKING->ptr = p;
	_task_scheduler_();
	p = (bool *)vTASKING->ptr;
	if(*p) goto __RET_TRUE;
	
__RET_FALSE:
	mExitCritical;
	return false;
	
__RET_TRUE:
	mExitCritical;
	return true;
}

/* 获取 */
bool __take_bin(bool _XDATA_MEM_ *p, tDelay tc)
{
	if(*p) goto __RET_TRUE;
	if(!tc) goto __RET_FALSE;
	
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __BINARY__ | sizeof(bool);
	vTASKING->ptr = p;
	_task_scheduler_();
	p = (bool *)vTASKING->ptr;
	if(*p) goto __RET_TRUE;
	
__RET_FALSE:
	mExitCritical;
	return false;
	
__RET_TRUE:
	*p = false;
	mExitCritical;
	return true;
}

#endif



/*
 * 计数信号量
 */
#if SYSCFG_SEMAPHORE == __ENABLED__
/* 获取 */
bool __take_sem(tSemSize _XDATA_MEM_ *c, tDelay tc)
{
	if(*c) goto __RET_TRUE;
	if(!tc) goto __RET_FALSE;
	
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __SEMAPHORE__ | sizeof(tSemSize);
	vTASKING->ptr = c;
	_task_scheduler_();
	c = (tSemSize *)vTASKING->ptr;
	if(*c) goto __RET_TRUE;
	
__RET_FALSE:
	mExitCritical;
	return false;
	
__RET_TRUE:
	(*c)--;
	mExitCritical;
	return true;
}

/* 释放 */
void __free_sem(tspSem p)
{
	if(p->counter < p->max)
	{
		p->counter++;
	}
	mExitCritical;
}

#endif



/*
 * 飞信
 */
#if SYSCFG_FETION == __ENABLED__
/* 接收飞信 */
static tFetion _recv_fetion_(tFetion _XDATA_MEM_ *tbox)
{
	tFetion tion = *tbox;
	*tbox = false;
	mExitCritical;
	return tion;
}

tFetion __recv_fetion(tFetion _XDATA_MEM_ *tbox, tDelay tc)
{
	if(*tbox) goto __RET_TION;
	if(!tc) goto __RET_FALSE;
	
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __RECV_FETION__ | sizeof(tFetion);
	vTASKING->ptr = tbox;
	_task_scheduler_();
	tbox = (tFetion *)vTASKING->ptr;
	
__RET_TION:
	return _recv_fetion_(tbox);
	
__RET_FALSE:
	mExitCritical;
	return false;
}

#endif



/*
 * 私信
 */
#if SYSCFG_DIRMSG == __ENABLED__
/* 接收私信 */
bool __recv_dm(tDM _XDATA_MEM_ *nf, tDelay tc)
{
	if(*nf) goto __RET_TRUE;
	if(!tc) goto __RET_FALSE;
	
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __RECV_DM__ | sizeof(tDM);
	vTASKING->ptr = nf;
	_task_scheduler_();
	nf = (tDM *)vTASKING->ptr;
	if(*nf) goto __RET_TRUE;
	
__RET_FALSE:
	mExitCritical;
	return false;
	
__RET_TRUE:
	*nf = false;
	return true;
}

#endif



/*
 * 消息邮箱
 */
#if SYSCFG_MAILBOX == __ENABLED__
/* 接收邮件 */
bool __recv_mail(bool _XDATA_MEM_ *gf, tDelay tc)
{
	if(*gf) goto __RET_TRUE;
	if(!tc) goto __RET_FALSE;
	
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __RECV_MAIL__ | sizeof(bool);
	vTASKING->ptr = gf;
	_task_scheduler_();
	gf = (bool *)vTASKING->ptr;
	if(*gf) goto __RET_TRUE;
	
__RET_FALSE:
	mExitCritical;
	return false;
	
__RET_TRUE:
	*gf = false;
	return true;
}

/* 发送邮件 */
void __send_mail(void _XDATA_MEM_ *gm, void *lm, size_t size, bool _XDATA_MEM_ *gf)
{
	#if SYSCFG_INTRECVMAIL == 0
	sWRITE_MBX_WRITE(gm);
	#elif SYSCFG_INTRECVMAIL == 1
	static tsMbxNode mbx_node;
	mbx_node.gmbx = gm;
	mbx_node.lmbx = lm;
	mbx_node.lnmf = true;
	sWRITE_MBX_WRITE(&mbx_node);
	#endif
	__memcpy(gm, lm, size);
	sWRITE_MBX_WRITE(NULL);
	#if SYSCFG_INTRECVMAIL == 0
	*gf = true;
	#elif SYSCFG_INTRECVMAIL == 1
	*gf = mbx_node.lnmf;
	#endif
	mExitCritical;
}

#endif



/*
 * 消息队列
 */
#if SYSCFG_MSGQUEUE == __ENABLED__
/* 接收消息 */
static void *_recv_msg_(void *p)
{
	mExitCritical;
	return p;
}

void *__recv_msg(tspMsgQueue msg_queue, tDelay tc)
{
	void *msg;
	tspMsgNode msg_node;
	msg_queue->mutex = false;
	if(msg_queue->counter) goto __RECV_MSG;
	msg_queue->mutex = true;
	if(!tc) goto __RET_NULL;
	
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __RECV_MSG__ | sizeof(size_t);
	vTASKING->ptr = msg_queue;
	_task_scheduler_();
	msg_queue = (tspMsgQueue)vTASKING->ptr;
	msg_queue->mutex = false;
	if(!msg_queue->counter) goto __FREE_MUTEX;
	
__RECV_MSG:
	if(msg_queue->type == __DYNAMIC__)
	{
		sRecvMsg_Dynamic(msg);
	}
	else
	{
		sRecvMsg_Static(msg);
	}
	msg_queue->mutex = true;
	return _recv_msg_(msg);
	
__FREE_MUTEX:
	msg_queue->mutex = true;
	
__RET_NULL:
	mExitCritical;
	return NULL;
}

/* 发送消息 */
tECODE __send_msg(tspMsgQueue msg_queue, void *msg)
{
	msg_queue->mutex = false;
	if(msg_queue->counter == msg_queue->len)
	{
		msg_queue->mutex = true;
		#if SYSCFG_DEBUGGING == __ENABLED__
		vAlarm.overflow_msgqueue = true;
		#endif
		mExitCritical;
		return ECODE_OVERFLOW_MSGQUEUE;
	}
	if(msg_queue->type == __DYNAMIC__)
	{
		tspMsgNode msg_node = NULL;
		msg_node = (tspMsgNode)__malloc(sizeof(tsMsgNode));
		if(msg_node == NULL)
		{
			msg_queue->mutex = true;
			#if SYSCFG_DEBUGGING == __ENABLED__
			vFault.mallocfail_msgnode = true;
			#endif
			mExitCritical;
			return ECODE_MALLOCFAIL_MSGNODE;
		}
		sSendMsg_Dynamic(msg);
	}
	else
	{
		sSendMsg_Static(msg);
	}
	msg_queue->mutex = true;
	mExitCritical;
	return ECODE_NOERR;
}

#endif



/*
 * 事件标志组
 */
#if SYSCFG_FLAGGROUP == __ENABLED__
/* 查询标志组 */
bool __query_grp(void _XDATA_MEM_ *p, u8 size)
{
	switch(size)
	{
		case 1: if(*(u8  *)p) goto __RET_TRUE; break;
		case 2: if(*(u16 *)p) goto __RET_TRUE; break;
		case 4: if(*(u32 *)p) goto __RET_TRUE; break;
	}
	mExitCritical;
	return false;
	
__RET_TRUE:
	mExitCritical;
	return true;
}

/* 等待标志组 */
bool __wait_grp(void _XDATA_MEM_ *p, u8 size, tDelay tc)
{
	switch(size)
	{
		case 1: if(*(u8  *)p) goto __RET_TRUE; break;
		case 2: if(*(u16 *)p) goto __RET_TRUE; break;
		case 4: if(*(u32 *)p) goto __RET_TRUE; break;
	}
	if(!tc) goto __RET_FALSE;
	
	vDELAY_STMR[vTASKING->TID] = tc;
	vTASKING->state = __BLOCKED__;
	vTASKING->blocktype = __FLAGGROUP__ | size;
	vTASKING->ptr = p;
	_task_scheduler_();
	p = vTASKING->ptr;
	size = vTASKING->blocktype & 0x0F;
	switch(size)
	{
		case 1: if(*(u8  *)p) goto __RET_TRUE; break;
		case 2: if(*(u16 *)p) goto __RET_TRUE; break;
		case 4: if(*(u32 *)p) goto __RET_TRUE; break;
	}
	
__RET_FALSE:
	mExitCritical;
	return false;
	
__RET_TRUE:
	mExitCritical;
	return true;
}

#endif



/*
 * 全局变量
 */

/* 全局变量写访问 */
void __write_gvar(void *gp, void *lp, size_t size)
{
	static tsVarNode var_node;
	var_node.gvar = gp;
	var_node.lvar = lp;
	sWRITE_VAR_WRITE(&var_node);
	size ? __memcpy(gp, lp, size) : __strcpy((char *)gp, (char *)lp);
	sWRITE_VAR_WRITE(NULL);
	mExitCritical;
}

/* 全局变量自运算 */
void __sope_gvar(void *gp, void *lp, tfpVV fp)
{
	static tsVarNode var_node;
	var_node.gvar = gp;
	var_node.lvar = lp;
	sWRITE_VAR_WRITE(&var_node);
	(*fp)();
	sWRITE_VAR_WRITE(NULL);
	mExitCritical;
}



/*
 * 动态内存
 */
#if SYSCFG_DYNMEMMGE == __ENABLED__
/* uxalloc */
void _MALLOC_MEM_ *__uxalloc(void _MALLOC_MEM_ *p)
{
	mExitCritical;
	return p;
}

/* 初始化线程内存池 */
bool __uinit_mempool(tspThrmem p, size_t size)
{
	p->p1 = p->p2 = __malloc(size);
	if(p->p1 == NULL)
	{
		mExitCritical;
		return false;
	}
	else
	{
		p->size = size;
		mExitCritical;
		return true;
	}
}

/* 线程内存分配 */
void _MALLOC_MEM_ *__talloc(tspThrmem p, size_t size)
{
	if(p->p1 == NULL || (size_t)p->p2 - (size_t)p->p1 + size > p->size)
	{
		return NULL;
	}
	else
	{
		void _MALLOC_MEM_ *r = p->p2;
		p->p2 = (u8 *)p->p2 + size;
		return r;
	}
}

#endif
